package com.genreate.util.erImg;

import cn.hutool.core.collection.ListUtil;
import com.genreate.domain.GenTable;
import com.genreate.util.DataBaseUtil;
import com.genreate.util.dbUtil.DbUtil;
import net.sourceforge.plantuml.FileFormat;
import net.sourceforge.plantuml.FileFormatOption;
import net.sourceforge.plantuml.SourceStringReader;
import net.sourceforge.plantuml.core.DiagramDescription;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

public class ERDiagramGenerator {
    public static Map<String, TableInfo> tableInfoMap = getTableAndColumnComments();

    public static void main(String[] args) {
        try {
            // 生成 PlantUML 源文本
            String plantUmlSource = generatePlantUMLSource(tableInfoMap);

            // 生成 ER 图
            File outputFile = new File("D:\\erdiagram1.png");
            SourceStringReader reader = new SourceStringReader(plantUmlSource);
            try (OutputStream os = new FileOutputStream(outputFile)) {
                DiagramDescription desc = reader.outputImage(os, new FileFormatOption(FileFormat.PNG));
                System.out.println("生成成功: " + desc.getDescription());
            }
            System.out.println("ER 图已保存至: " + outputFile.getAbsolutePath());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 手动设置外键
     * key 左边是表.右边是字段
     * value   左边是表.右边是字段
     *表示对应的是value表字段的外键
     * @return {@link Map }<{@link String },{@link String }>
     */
    public static Map<String,String> getMapPk(){
        Map<String,String> map = new HashMap<>();
        map.put("emergency_command_dispatch_log.event_id", "emergency_events_details.id");
        map.put("emergency_drill_plan.connect_event_plan_id", "emergency_events_plan_library.id");
        map.put("emergency_drill_plan_script.drill_plan_id", "emergency_drill_plan.id");
        map.put("emergency_drill_task.plan_id", "emergency_drill_plan.id");
        map.put("emergency_drill_task_script.drill_task_id", "emergency_drill_task.id");
        map.put("emergency_events_case_library.connect_event_id", "emergency_events_details.id");
        map.put("emergency_events_details.connect_plan", "emergency_events_plan_library.id");
        map.put("emergency_events_details.historical_plan", "emergency_events_case_library.id");
        map.put("emergency_events_group_chat.event_id", "emergency_events_details.id");
        map.put("emergency_events_info_publish_log.event_id", "emergency_events_details.id");
        map.put("emergency_events_meeting.event_id", "emergency_events_details.id");
        map.put("emergency_events_operation_details.connect_event_id", "emergency_events_details.id");
        map.put("emergency_events_picture_send_log.event_id", "emergency_events_details.id");
        map.put("emergency_events_plan_deal_info.plan_id", "emergency_events_plan_library.id");
        map.put("emergency_events_plan_deal_info_disposal.plan_id", "emergency_events_plan_library.id");
        map.put("emergency_events_plan_deal_info_disposal.event_id", "emergency_events_details.id");
        map.put("emergency_events_plan_deal_info_disposal.info_id", "emergency_events_plan_deal_info.id");
        map.put("emergency_events_plan_library.connect_event_id", "emergency_events_details.id");

//        map.put("emergency_events_report_upload_list.event_id", "emergency_events_details.id");
//        map.put("emergency_events_response_organization.event_id", "emergency_events_details.id");
//        map.put("emergency_events_response_organization.organization_id", "emergency_personnel_organization.organization_id");
//        map.put("emergency_events_response_organization.personnel_id", "emergency_personnel_details.id");
//        map.put("emergency_events_system_log.event_id", "emergency_events_details.id");
//        map.put("emergency_events_up_down_log.event_id", "emergency_events_details.id");
//        map.put("emergency_personnel_details.organization_id", "emergency_personnel_organization.organization_id");
//        map.put("emergency_sensitive_time_remind.event_id", "emergency_events_details.id");
//        map.put("emergency_sms_log.event_id", "emergency_events_details.id");
//        map.put("emergency_supplies_details.position_id", "emergency_supplies_position.position_id");
//        map.put("emergency_supplies_push.suoolies_id", "emergency_specialist_details.id");
//        map.put("emergency_training_plan.source_id", "emergency_training_requirements.id");
//        map.put("emergency_training_plan.history_event", "emergency_events_case_library.id");
//        map.put("emergency_training_plan_progress.train_id", "emergency_training_plan.id");
//        map.put("emergency_training_requirements.history_event", "emergency_events_case_library.id");
//        map.put("emergency_video_list.event_id", "emergency_events_details.id");
//        map.put("emergency_video_list_many.pid", "emergency_video_list.id");
        return map;
    }


    // 表信息类

    // 从数据库获取表和字段注释
    private static Map<String, TableInfo> getTableAndColumnComments() {
        Map<String, TableInfo> tableInfoMap = new HashMap<>();
        List<String> emergency = DataBaseUtil.getAllTableNames("emergency");
        String tableStr = "emergency_command_dispatch_log\n" +
                "emergency_drill_plan\n" +
                "emergency_drill_plan_script\n" +
                "emergency_drill_task\n" +
                "emergency_drill_task_script\n" +
                "emergency_events_case_library\n" +
                "emergency_events_details\n" +
                "emergency_events_group_chat\n" +
                "emergency_events_info_publish_log\n" +
                "emergency_events_meeting\n" +
                "emergency_events_operation_details\n" +
                "emergency_events_personnel_log\n" +
                "emergency_events_picture_send_log\n" +
                "emergency_events_plan_deal_info\n" +
                "emergency_events_plan_deal_info_disposal\n" +
                "emergency_events_plan_library";
        List<String> strings = ListUtil.toList(tableStr.split("\n"));
        for (String tableName : emergency) {
            if(!strings.contains(tableName)){
                continue;
            }
            TableInfo tableInfo = new TableInfo();
            GenTable table = DbUtil.queryToCamelCase(DbUtil.getTableSql("mysql",tableName),GenTable.class);
            tableInfo.setComment(table.getTableComment());
            List<ColumnInfo> columns = DbUtil.getTableColumn("mysql", tableName)
                    .stream()
                    .map(e->{
                        ColumnInfo res = new ColumnInfo();
                        res.setComment(e.getColumnComment());
                        res.setType(e.getColumnType());
                        res.setName(e.getColumnName());
                        res.setPrimaryKey(e.isPk());
                        return res;
                    }).collect(Collectors.toList());
            tableInfo.setColumns(columns);
            tableInfoMap.put(tableName, tableInfo);
        }

        return tableInfoMap;
    }

    // 生成 PlantUML 源文本
    private static String generatePlantUMLSource(Map<String, TableInfo> tableInfoMap) {
        StringBuilder sb = new StringBuilder("@startuml\n");
        // 添加这行设置方向为从上到下
        sb.append("left to right direction\n");
        sb.append("skinparam monochrome true\n");
        sb.append("skinparam linetype ortho\n");
        sb.append("skinparam entity {\n");
        sb.append("    BackgroundColor LightBlue\n");
        sb.append("    BorderColor Blue\n");
        sb.append("    ArrowColor Blue\n");
        sb.append("}\n\n");
        
        for (Map.Entry<String, TableInfo> entry : tableInfoMap.entrySet()) {
            String tableName = entry.getKey();
            TableInfo tableInfo = entry.getValue();
            
            // 表标题使用表注释
            sb.append("entity \"").append( tableInfo.getComment())
                    .append("\" as ").append(tableName)
                    .append(" {\n");
            
            // 如果有表注释，作为标题显示
//            if (tableInfo.getComment() != null) {
//                sb.append("    \n");
//                sb.append("    ").append(tableName).append("\n");
//                sb.append("    --\n");
//            }
            
            // 字段按需求排列：注释 | 类型 | 键 | 字段名
//            sb.append("    <<Fields>>\n");
            for (ColumnInfo column : tableInfo.getColumns()) {
                String keyType = column.isPrimaryKey ? "PK" : 
                                (column.isForeignKey ? "FK" : "");
                sb.append("    ").append(column.comment).append(" : ").append(column.type)
                  .append(" : ").append(keyType).append(" : ").append(column.name).append("\n");
            }
            
            sb.append("}\n\n");
        }
        
        // 添加表关系（此处简化处理，实际需根据外键生成）
        addTableRelationships(sb);
        
        sb.append("@enduml");
        return sb.toString();
    }


    /**
     * 添加表之间的关系到 PlantUML 源文本
     * @param sb 用于构建 PlantUML 源文本的 StringBuilder
     */
    private static void addTableRelationships(StringBuilder sb) {
        Map<String, String> mapPk = getMapPk();

        //怎么将手动设置的外键，关联上
        // 遍历所有手动设置的外键关系
        for (Map.Entry<String, String> entry : mapPk.entrySet()) {
            String[] fromParts = entry.getKey().split("\\.");
            String[] toParts = entry.getValue().split("\\.");

            if (fromParts.length != 2 || toParts.length != 2) {
                System.err.println("外键关系格式错误: " + entry.getKey() + " -> " + entry.getValue());
                continue;
            }

            String fromTable = fromParts[0];
            String fromColumn = fromParts[1];
            String toTable = toParts[0];
            String toColumn = toParts[1];

            // 检查表是否存在
            if (!tableInfoMap.containsKey(fromTable) || !tableInfoMap.containsKey(toTable)) {
                System.err.println("表不存在: " + fromTable + " 或 " + toTable);
                continue;
            }

            // 检查字段是否存在
            boolean fromColumnExists = tableInfoMap.get(fromTable).getColumns().stream()
                    .anyMatch(col -> col.getName().equals(fromColumn));
            boolean toColumnExists = tableInfoMap.get(toTable).getColumns().stream()
                    .anyMatch(col -> col.getName().equals(toColumn));

            if (!fromColumnExists || !toColumnExists) {
                System.err.println("字段不存在: " + fromTable + "." + fromColumn + " 或 " + toTable + "." + toColumn);
                continue;
            }

            // 添加关联关系
            // 假设是一对多关系（多端指向一端）
            sb.append(fromTable).append(" }o--|| ").append(toTable)
                    .append(" : \"").append(fromColumn).append(" → ").append(toColumn).append("\"\n");
        }
    }

}